﻿#region Copyright & licence

// This file is part of Refix.
// 
// Refix is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
// 
// Refix is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public
// License along with Refix.  If not, see <http://www.gnu.org/licenses/>.
// 
// Copyright (C) 2010-11 David Musgrove and others.

#endregion

using System;
using System.IO;

using Moq;

using NUnit.Framework;

using Refix.Core;
using Refix.Core.Repository;
using Refix.RepositoryBrowser.Models;

namespace Refix.RepositoryBrowser.Tests.Models
{
    [TestFixture]
    public class RepositoryModelFactoryTests
    {
        [Test]
        public void ConstructModel_ReportsInitialStatusOnModel()
        {
            var mockModel = new Mock<IRepositoryModel>();
            string directoryName = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"));

            mockModel.Setup(m => m.ReportStatus(It.Is<string>(s => !s.IsNullOrEmpty())))
                .Verifiable("ReportStatus should be called by Construct method.");

            var factory = new RepositoryModelFactory(directoryName);

            factory.ConstructModel(mockModel.Object);

            mockModel.VerifyAll();
        }

        [Test]
        public void ConstructModel_ReturnsEmptyRepositoryItemForNonExistentDirectory()
        {
            var mockModel = new Mock<IRepositoryModel>();
            string directoryName = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"));

            var factory = new RepositoryModelFactory(directoryName);

            RepositoryItem item = factory.ConstructModel(mockModel.Object);

            Assert.IsNotNull(item,
                "RepositoryItem returned for a non-existent directory should not be null.");
            Assert.AreEqual(0, item.Children.Count,
                "RepositoryItem returned for a non-existent directory should have zero child items.");
        }

        [Test]
        public void ConstructModel_AddsItemsForDirectoriesContainingComponents()
        {
            var mockModel = new Mock<IRepositoryModel>();
            var mockRepository = new Mock<ILocalRepository>();
            
            string directoryName = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"));
            Directory.CreateDirectory(directoryName);
            Directory.CreateDirectory(Path.Combine(directoryName, "Comp1"));
            Directory.CreateDirectory(Path.Combine(Path.Combine(directoryName, "Comp1"), "1.0.0.0"));
            Directory.CreateDirectory(Path.Combine(directoryName, "Comp2"));
            Directory.CreateDirectory(Path.Combine(Path.Combine(directoryName, "Comp2"), "1.0.0.0"));

            var component = new Component
                            {
                                Name = "Comp1",
                                Versions =
                                    {
                                        new ComponentVersion {Number = "1.0.0.0"}
                                    }
                            };

            mockRepository.SetupGet(r => r.BaseDirectory)
                .Returns(directoryName);
            mockModel.Setup(m => m.ReportStatus(It.IsAny<string>()));

            mockRepository.Setup(r => r.GetComponent("Comp1", false))
                .Returns(component)
                .Verifiable("ConstructModel method should call GetComponent method on repository for Comp1.");
            mockRepository.Setup(r => r.GetComponent("Comp2", false))
                .Returns((Component)null)
                .Verifiable("ConstructModel method should call GetComponent method on repository for Comp2.");

            var factory = new RepositoryModelFactory
                          {
                              Repository = mockRepository.Object
                          };

            RepositoryItem item = factory.ConstructModel(mockModel.Object);

            Assert.Greater(item.Children.Count, 0,
                "ConstructModel should have added a child for the matched component.");
            Assert.AreEqual(RepositoryItemState.Component, item.Children[0].State,
                "ConstructModel should have set appropriate state for the matched component.");
            Assert.AreSame(component, item.Children[0].Component,
                "ConstructModel should have set Component property on child item.");

            Directory.Delete(directoryName, true);
        }

        [Test]
        public void ConstructModel_DoesntAddItemsForDirectoriesNotContainingComponents()
        {
            var mockModel = new Mock<IRepositoryModel>();
            var mockRepository = new Mock<ILocalRepository>();

            string directoryName = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"));
            Directory.CreateDirectory(directoryName);
            Directory.CreateDirectory(Path.Combine(directoryName, "Comp1"));
            Directory.CreateDirectory(Path.Combine(Path.Combine(directoryName, "Comp1"), "1.0.0.0"));
            Directory.CreateDirectory(Path.Combine(directoryName, "Comp2"));
            Directory.CreateDirectory(Path.Combine(Path.Combine(directoryName, "Comp2"), "1.0.0.0"));

            mockRepository.SetupGet(r => r.BaseDirectory)
                .Returns(directoryName);
            mockModel.Setup(m => m.ReportStatus(It.IsAny<string>()));

            mockRepository.Setup(r => r.GetComponent("Comp1", false))
                .Returns((Component)null)
                .Verifiable("ConstructModel method should call GetComponent method on repository for Comp1.");
            mockRepository.Setup(r => r.GetComponent("Comp2", false))
                .Returns((Component)null)
                .Verifiable("ConstructModel method should call GetComponent method on repository for Comp2.");

            var factory = new RepositoryModelFactory
            {
                Repository = mockRepository.Object
            };

            RepositoryItem item = factory.ConstructModel(mockModel.Object);

            Assert.AreEqual(0, item.Children.Count,
                "ConstructModel should not have added a child for directories witout components.");

            Directory.Delete(directoryName, true);
        }
    }
}